package nl.blindwars.mapeditor.gui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.GroupLayout;

import nl.blindwars.model.City;

public class DrawWindow extends MyJPanel implements MouseListener, MouseMotionListener {
	private static final long serialVersionUID = -2746897652917394829L;

	// Points to store the points of a drag movement in.
	private ArrayList<Point> points = new ArrayList<Point>();
	
	private ArrayList<City> cities = new ArrayList<City>();
	
	protected Window window;

	private GroupLayout layout;
	
	// Cursors:
	private static final Cursor pointerCursor = new Cursor(0);
	private static final Cursor crossCursor = new Cursor(1);
	
	private boolean drawModeOn = false;
	
	// Keep track of the state of the left button.
	private boolean leftButtonPressed = false;
	
	public DrawWindow(Window window, int width, int height) {
		super();

		this.window = window;
		
		setSize(width, height);
		
		setBackground(Color.WHITE);
		
		layout = new GroupLayout(this);
		
		setLayout(layout);
		
		setOpaque(true);
		
		addMouseListener(this);
		addMouseMotionListener(this);
	}

	private void drawPoint() {
		if(points.size() > 1) {
			Graphics g = getGraphics();
			
			Graphics2D g2d = (Graphics2D)g;
			g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
			
			Point lastPoint = points.get(points.size() - 1);
			Point previousPoint = points.get(points.size() - 2);
			g.drawLine(previousPoint.x, previousPoint.y, lastPoint.x, lastPoint.y);
		}
	}
	
	/**
	 * Paint the label for a newly craeted city.
	 */
	private void drawCityLabel(City city) {
		Point p = city.getCenter();
		Graphics g = getGraphics();
//		System.out.println("City " + cities.size() + " " + p.x + " x " + p.y);
		g.drawString("City " + cities.size(), p.x, p.y);
//		JLabel label = new JLabel("City " + cities.size());
//		label.setLocation(p);
		
//		layout.setHorizontalGroup(
//		   layout.createSequentialGroup().addComponent(label)
//		);
//		layout.setVerticalGroup(
//		   layout.createSequentialGroup().addComponent(label)
//		);
	}
	
	/**
	 * Tie the ends of two lines together when drawing a border to make it a closed line.
	 */
	private void tieEnds() {
		if(points.size() > 1) {
			Point lastPoint = points.get(points.size() - 1);
			Point firstPoint = points.get(0);
			
			tiePoints(lastPoint, firstPoint);
			
			createCity();
		}
	}
		
	/**
	 * Create points between the two given points to draw a line.
	 * @param Point p1 The starting point. 
	 * @param Point p2 The destination point.
	 */
	private void tiePoints(Point p1, Point p2) {
		int beginX = p1.x;
		int beginY = p1.y;
		int destX = p2.x;
		int destY = p2.y;
		
		int distanceX = beginX - destX;
		int distanceY = beginY - destY;
		
		int distance = (distanceX > distanceY) ? distanceX : distanceY;
		
		double stepX = (double) distanceX / (double) distance;
		double stepY = (double) distanceY / (double) distance;
		
//		System.out.println(distance + " From: " + p1.x + " x " + p1.y + " To: " + p2.x + " x " + p2.y);
		
		if(distance > 0) {
			for(int i = Math.abs(distance); i > 0; i--) {
				int x = (int) Math.round(i * stepX) + destX;
				int y = (int) Math.round(i * stepY) + destY;
				points.add(new Point(x, y));
				drawPoint();
			}
		} else {
			for(int i = distance; i < 0; i++) {
				int x = (int) Math.round(i * stepX) + destX;
				int y = (int) Math.round(i * stepY) + destY;
				points.add(new Point(x, y));
				drawPoint();
			}
		}
	}

	private void createCity() {
		toggleDrawMode();
		
		City city = new City(points);
		drawCityLabel(city);
		cities.add(city);

		points.clear();
		
	}
	
	/**
	 * Turn on/off the draw mode.
	 */
	public void toggleDrawMode() {
		if(drawModeOn) {
			drawModeOn = false;
			setCursor(pointerCursor);
			System.out.println("Stopped drawing");
		} else {
			drawModeOn = true;
			setCursor(crossCursor);
			System.out.println("Drawing");
		}
	}
	
	@Override
	public void mouseClicked(MouseEvent e) {}

	@Override
	public void mouseEntered(MouseEvent e) {}

	@Override
	public void mouseExited(MouseEvent e) {}

	@Override
	public void mousePressed(MouseEvent e) {
		if(e.getButton() == MouseEvent.BUTTON1) {
			leftButtonPressed = true;
		}
		
		if(drawModeOn && points.size() > 0) {
//			Point lastPoint = points.get(points.size() - 1);
//			Point destinationPoint = e.getPoint();
//			tiePoints(lastPoint, destinationPoint);

			//debug:
//			Point p = points.get(points.size() - 1);
//			System.out.println("Draw line from: " + p.x + " x " + p.y);
//			p = e.getPoint();
//			System.out.println("to: " + p.x + " x " + p.y);
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		leftButtonPressed = false;
		if(drawModeOn && e.getButton() == MouseEvent.BUTTON3) {
			tieEnds();
		}
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		if(drawModeOn && leftButtonPressed) {
			points.add(e.getPoint());
			drawPoint();
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		window.setMouseCoordinates(e.getPoint());
		if(!drawModeOn) {
//			System.out.println(e.getSource());
		}
	}
	
}
